#include <map>

#include <json/json.h>

#include "metrics/MetricFamily.hpp"
#include "metrics/MetricType.hpp"
#include "metrics/ClientMetric.hpp"
#include "metrics/JsonMetricFormatter.hpp"

namespace metrics
{
    JsonMetricFormatter::JsonMetricFormatter()
    {
    }

    JsonMetricFormatter::~JsonMetricFormatter()
    {
    }

    /*
    json格式为：
    {
        "name": "",
        "help": "",
        "type": "Counter",
        "time": 1637564934609041676,
        "labels": {"l1":"v1", "l2":"v2"},
        "value": 111111
    }
    */

    std::vector<std::string> JsonMetricFormatter::format(const MetricFamily &mf)
    {
        auto add_labels = [](Json::Value &labels, const std::map<std::string, std::string> &map)
        {
            for (auto &label : map)
            {
                labels[label.first] = label.second;
            }
        };

        std::vector<std::string> jsons;

        Json::Value family_labels;
        add_labels(family_labels, mf.labels);

        Json::StreamWriterBuilder builder;
        Json::Value root;

        root["name"] = mf.name;
        root["help"] = mf.help;
        root["time"] = std::chrono::duration_cast<std::chrono::nanoseconds>(mf.date.time_point().time_since_epoch()).count();
        root["date"] = mf.date.format();
        root["type"] = metric_type_to_str(mf.type);
        //add metric values
        for (auto &metric : mf.metric)
        {
            //add metric labels
            root["labels"] = family_labels;
            add_labels(root["labels"], metric.labels);

            //add value
            switch (mf.type)
            {
            case MetricType::Counter:
            {
                root["value"] = metric.counter.value;
                break;
            }
            case MetricType::Gauge:
            {
                root["value"] = metric.gauge.value;
                break;
            }
            case MetricType::Histogram:
            {
                Json::Value h;
                Json::Value buckets;
                for (auto &bucket : metric.histogram.buckets)
                {
                    Json::Value item;
                    item["count"] = bucket.cumulative_count;
                    item["upper_bound"] = bucket.upper_bound;
                    buckets.append(item);
                }
                h["count"] = metric.histogram.sample_count;
                h["sum"] = metric.histogram.sample_sum;
                h["buckets"] = buckets;
                root["value"] = h;
                break;
            }
            default:
            {
                root["value"] = 0;
                break;
            }
            }

            std::string json = Json::writeString(builder, root);
            jsons.push_back(json);
        }

        return jsons;
    }

} // namespace metrics